﻿using Newtonsoft.Json;
using SimpleRPC.Client;
using SimpleRPC.Handler;
using SimpleRPC.Message;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SimpleRPC
{
    public class RpcClientProxy : DynamicObject
    {
        public string ServerIp { get; set; }
        public int ServerPort { get; set; }
        public string ServiceName { get; set; }
        public Type ServiceType { get; set; }
        private static ClientWait _clientWait { get; } = new ClientWait();
        private Socket _client { get; set; }

        private LengthFieldEncoder _lengthFieldEncoder;
        public RpcClientProxy()
        {
            _lengthFieldEncoder = new LengthFieldEncoder();
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            try
            {
                Response response = null;
                try
                {
                    if (_client == null)
                    {
                        _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        _client.Connect(new IPEndPoint(IPAddress.Parse(ServerIp), ServerPort));
                        Task.Factory.StartNew(() =>
                        {
                            ReceiveHandler(_client);
                        });
                    }
                }
                catch
                {
                    throw new Exception("连接到服务器失败!");
                }
                if (_client != null)
                {
                    var waitId = _client.LocalEndPoint.ToString();
                    _clientWait.Start(waitId);
                    Request request = new Request
                    {
                        ServiceName = ServiceName,
                        MethodName = binder.Name,
                        Paramters = args.ToList()
                    };
                    var buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(request));
                    // 前两个字节为包长度 
                    _lengthFieldEncoder.Encode(buffer, out byte[] sendBuffer);
                    
                    _client.Send(sendBuffer);
                    var responseString = _clientWait.Wait(waitId).ResponseString;
                    try
                    {
                        response = JsonConvert.DeserializeObject<Response>(responseString);
                    }
                    catch
                    {
                        response = null;
                    }
                }

                if (response == null)
                    throw new Exception("服务器超时未响应");
                else if (response.Success)
                {
                    Type returnType = ServiceType.GetMethod(binder.Name).ReturnType;
                    if (returnType == typeof(void))
                        result = null;
                    else
                        result = JsonConvert.DeserializeObject(response.Data, returnType);

                    return true;
                }
                else
                    throw new Exception($"服务器异常，错误消息：{response.Message}");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void ReceiveHandler(Socket client)
        {
            var waitId = client.LocalEndPoint.ToString();
            int len = 0;
            List<byte> buffer = new List<byte>(512 * 1024);
            while (true)
            {
                byte[] buf = new byte[4 * 1024];
                try
                {
                    len = client.Receive(buf);
                }
                catch
                {
                    break;
                }
                if (len > 0)
                {
                    if (len == buf.Length)
                    {
                        buffer.AddRange(buf);
                    }
                    else
                    {
                        buffer.AddRange(buf.Take(len));
                    }
                    // 前两个字节为长度
                    var frameLen = BitConverter.ToInt16(buffer.Take(2).ToArray(), 0);
                    if (buffer.Count >= frameLen + 2)
                    {
                        var frame = buffer.Skip(2).Take(frameLen).ToArray();
                        buffer.RemoveRange(0, frameLen + 2);

                        _clientWait.Set(waitId, Encoding.UTF8.GetString(frame));
                    }
                }
                else
                {
                    break;
                }
            }
            _clientWait.Clear(waitId);
            // 断开连接
            _client = null;
        }
    }
}
